import {MESSAGE_TYPE, MESSAGE_STATUS} from "../api/enums.js"
import userStore from './userStore';
import localForage from 'localforage';

// In order to accelerate the efficiency of pulling offline messages, the messages are temporarily stored in cacheChats during the pulling process, and after all offline messages are pulled, they are uniformly placed in Vuex for rendering
let cacheChats = [];

export default {
    state: {
        activeChat: null,
        privateMsgMaxId: 0,
        groupMsgMaxId: 0,
        loadingPrivateMsg: false,
        loadingGroupMsg: false,
        chats: []
    },

    mutations: {
        initChats(state, chatsData) {
            state.chats = [];
            state.privateMsgMaxId = chatsData.privateMsgMaxId || 0;
            state.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
            cacheChats = chatsData.chats || [];
            // Prevent images from being continuously loaded
            cacheChats.forEach((chat) => {
                chat.messages.forEach((msg) => {
                    if (msg.loadStatus == "loading") {
                        msg.loadStatus = "fail"
                    }
                })
            })
        },
        openChat(state, chatInfo) {
            let chats = this.getters.findChats()
            console.log('chats', chats)
            let chat = null;
            for (let idx in chats) {
                if (chats[idx].type == chatInfo.type &&
                    chats[idx].targetId === chatInfo.targetId) {
                    chat = chats[idx];
                    // Place the head
                    this.commit("moveTop", idx)
                    break;
                }
            }
            // Create session
            if (chat == null) {
                chat = {
                    targetId: chatInfo.targetId,
                    type: chatInfo.type,
                    showName: chatInfo.showName,
                    headImage: chatInfo.headImage,
                    lastContent: "",
                    lastSendTime: new Date().getTime(),
                    unreadCount: 0,
                    messages: [],
                    atMe: false,
                    atAll: false,
                    stored: false,
                    delete: false
                };
                chats.unshift(chat);
            }
            console.log('this.$store.state.chats', state.chats)
            cacheChats = chats
            this.commit("refreshChats")
        },
        activeChat(state, idx) {
            let chats = this.getters.findChats();
            state.activeChat = chats[idx];
        },
        resetUnreadCount(state, chatInfo) {
            let chats = this.getters.findChats();
            for (let idx in chats) {
                if (chats[idx].type == chatInfo.type &&
                    chats[idx].targetId == chatInfo.targetId) {
                    chats[idx].unreadCount = 0;
                    chats[idx].atMe = false;
                    chats[idx].atAll = false;
                    chats[idx].stored = false;
                    this.commit("saveToStorage");
                    break;
                }
            }
        },
        readedMessage(state, pos) {
            let chat = this.getters.findChatByFriend(pos.friendId);
            chat.messages.forEach((m) => {
                if (m.id && m.selfSend && m.status < MESSAGE_STATUS.RECALL) {
                    // pos.maxId is empty means the entire session has been read
                    if (!pos.maxId || m.id <= pos.maxId) {
                        m.status = MESSAGE_STATUS.READED
                        chat.stored = false;
                    }
                }
            })
            this.commit("saveToStorage");
        },
        removeChat(state, idx) {
            let chats = this.getters.findChats();
            if (chats[idx] == state.activeChat) {
                state.activeChat = null;
            }
            chats[idx].delete = true;
            chats[idx].stored = false;
            this.commit("saveToStorage");
        },
        removePrivateChat(state, friendId) {
            let chats = this.getters.findChats();
            for (let idx in chats) {
                if (chats[idx].type == 'PRIVATE' &&
                    chats[idx].targetId === friendId) {
                    this.commit("removeChat", idx)
                    break;
                }
            }
        },
        removeGroupChat(state, groupId) {
            let chats = this.getters.findChats();
            for (let idx in chats) {
                if (chats[idx].type == 'GROUP' &&
                    chats[idx].targetId === groupId) {
                    this.commit("removeChat", idx)
                    break;
                }
            }
        },
        moveTop(state, idx) {
            // Not moving during loading, which consumes a lot of performance
            if (this.getters.isLoading()) {
                return;
            }
            if (idx > 0) {
                let chats = this.getters.findChats();
                let chat = chats[idx];
                chats.splice(idx, 1);
                chats.unshift(chat);
                chat.lastSendTime = new Date().getTime();
                chat.stored = false;
                this.commit("saveToStorage");
            }
        },
        insertMessage(state, msgInfo) {

            var cryptoInstance = this.getters.cryptoInstance();
            var plainText
            if (msgInfo.code) {
                plainText = cryptoInstance.cryptoUtil.decryptText(cryptoInstance, {keyEncrypted: msgInfo.sendCke, content: msgInfo.content});
                cryptoInstance.cryptoUtil.toNotEncrypted(msgInfo, plainText)
            } else {
                // console.log('insertMessage ', plainText)
            }

            let type = msgInfo.groupId ? 'GROUP' : 'PRIVATE';
            // Record the maximum ID of the message
            if (msgInfo.id && type == "PRIVATE" && msgInfo.id > state.privateMsgMaxId) {
                state.privateMsgMaxId = msgInfo.id;
            }
            if (msgInfo.id && type == "GROUP" && msgInfo.id > state.groupMsgMaxId) {
                state.groupMsgMaxId = msgInfo.id;
            }
            // If the message already exists, overwrite the old message data
            let chat = this.getters.findChat(msgInfo);
            console.log('------------------insertMessage', state, msgInfo, chat)
            let message = this.getters.findMessage(chat, msgInfo);
            if (message) {
                Object.assign(message, msgInfo);
                // Withdrawal message needs to be displayed
                if (msgInfo.type == MESSAGE_TYPE.RECALL) {
                    chat.lastContent = msgInfo.content;
                }
                chat.stored = false;
                this.commit("saveToStorage");
                return;
            }
            // msgInfo
            if (msgInfo.type == MESSAGE_TYPE.IMAGE) {
                chat.lastContent = "[Image]";
            } else if (msgInfo.type == MESSAGE_TYPE.FILE) {
                chat.lastContent = "[File]";
            } else if (msgInfo.type == MESSAGE_TYPE.AUDIO) {
                chat.lastContent = "[Voice]";
            } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) {
                chat.lastContent = "[Voice Call]";
            } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) {
                chat.lastContent = "[Video Call]";
            } else if (msgInfo.type == MESSAGE_TYPE.TEXT ||
                msgInfo.type == MESSAGE_TYPE.RECALL ||
                msgInfo.type == MESSAGE_TYPE.TIP_TEXT) {
                chat.lastContent = msgInfo.content;
            }
            chat.lastSendTime = msgInfo.sendTime;
            chat.sendNickName = msgInfo.sendNickName;
            // unread+1
            if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) {
                chat.unreadCount++;
            }
            // Has anyone @ me
            if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds &&
                msgInfo.status != MESSAGE_STATUS.READED) {
                let userId = userStore.state.userInfo.id;
                if (msgInfo.atUserIds.indexOf(userId) >= 0) {
                    chat.atMe = true;
                }
                if (msgInfo.atUserIds.indexOf(-1) >= 0) {
                    chat.atAll = true;
                }
            }
            // Insertion time display with an interval greater than 10 minutes
            if (!chat.lastTimeTip || (chat.lastTimeTip < msgInfo.sendTime - 600 * 1000)) {
                chat.messages.push({
                    sendTime: msgInfo.sendTime,
                    type: MESSAGE_TYPE.TIP_TIME,
                });
                chat.lastTimeTip = msgInfo.sendTime;
            }
            // Insert according to the order of IDs to prevent message disorder
            let insertPos = chat.messages.length;
            // Prevent images and files from appearing at the top on the sender's end because they have not been saved yet, id=0
            if (msgInfo.id && msgInfo.id > 0) {
                for (let idx in chat.messages) {
                    if (chat.messages[idx].id && msgInfo.id < chat.messages[idx].id) {
                        insertPos = idx;
                        console.log(`The message appears out of order, location:${chat.messages.length},Revised to:${insertPos}`);
                        break;
                    }
                }
            }
            chat.messages.splice(insertPos, 0, msgInfo);
            chat.stored = false;
            if (state.activeChat && state.activeChat.targetId === chat.targetId) {
                state.activeChat = chat;
            }
            this.commit("saveToStorage");
        },
        updateMessage(state, msgInfo) {
            // Get the other party's ID or group ID
            let chat = this.getters.findChat(msgInfo);
            let message = this.getters.findMessage(chat, msgInfo);
            if (message) {
                // Attribute copy
                Object.assign(message, msgInfo);
                chat.stored = false;
                this.commit("saveToStorage");
            }
        },
        deleteMessage(state, msgInfo) {
            let chat = this.getters.findChat(msgInfo);
            for (let idx in chat.messages) {
                // Successfully sent, delete based on ID
                if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) {
                    chat.messages.splice(idx, 1);
                    break;
                }
                // The message being sent may not have an ID, please delete it based on the sending time
                if (msgInfo.selfSend && chat.messages[idx].selfSend &&
                    chat.messages[idx].sendTime == msgInfo.sendTime) {
                    chat.messages.splice(idx, 1);
                    break;
                }
            }
            chat.stored = false;
            this.commit("saveToStorage");
        },
        deleteMessages(state, msgInfos) {
            const modifiedChats = new Set()

            msgInfos.forEach(msgInfo => {
                let chat = this.getters.findChat(msgInfo)
                if (!chat) return

                for (let i = chat.messages.length - 1; i >= 0; i--) {
                    const msg = chat.messages[i]

                    if (msg.id && msg.id === msgInfo.id) {
                        chat.messages.splice(i, 1)
                        modifiedChats.add(chat)
                        break
                    }

                    if (msgInfo.selfSend && msg.selfSend &&
                        msg.sendTime === msgInfo.sendTime) {
                        chat.messages.splice(i, 1)
                        modifiedChats.add(chat)
                        break
                    }
                }
            })

            modifiedChats.forEach(chat => {
                chat.stored = false
            })

            if (modifiedChats.size > 0) {
                this.commit("saveToStorage")
            }
        },
        updateChatFromFriend(state, friend) {
            let chat = this.getters.findChatByFriend(friend.id);
            // Update the group name and avatar in the conversation
            if (chat && (chat.headImage != friend.headImageThumb ||
                chat.showName != friend.nickName)) {
                chat.headImage = friend.headImageThumb;
                chat.showName = friend.nickName;
                chat.stored = false;
                this.commit("saveToStorage")
            }
        },
        updateChatFromGroup(state, group) {
            let chat = this.getters.findChatByGroup(group.id);
            if (chat && (chat.headImage != group.headImageThumb ||
                chat.showName != group.remarkGroupName)) {
                // Update the group name and avatar in the conversation
                chat.headImage = group.headImageThumb;
                chat.showName = group.remarkGroupName;
                chat.stored = false;
                this.commit("saveToStorage")
            }
        },
        loadingPrivateMsg(state, loading) {
            state.loadingPrivateMsg = loading;
            if (!this.getters.isLoading()) {
                this.commit("refreshChats")
            }
        },
        loadingGroupMsg(state, loading) {
            state.loadingGroupMsg = loading;
            if (!this.getters.isLoading()) {
                this.commit("refreshChats")
            }
        },
        refreshChats(state) {
            if (!cacheChats) {
                return;
            }
            cacheChats.sort((chat1, chat2) => {
                return chat2.lastSendTime - chat1.lastSendTime;
            });
            // Load the message back at once
            state.chats = cacheChats;
            // Clear cache and no longer use
            cacheChats = null;
            this.commit("saveToStorage");
        },
        saveToStorage(state) {
            // Do not save during loading to prevent lagging
            if (this.getters.isLoading()) {
                return;
            }
            let userId = userStore.state.userInfo.id;
            let key = "chats-" + userId;
            let chatKeys = [];
            // Store by session unit，
            state.chats.forEach((chat) => {
                // Only store sessions that have been modified
                let chatKey = `${key}-${chat.type}-${chat.targetId}`
                if (!chat.stored) {
                    console.log(chatKey)
                    if (chat.delete) {
                        localForage.removeItem(chatKey);
                    } else {
                        localForage.setItem(chatKey, chat);
                    }
                    chat.stored = true;
                }
                if (!chat.delete) {
                    chatKeys.push(chatKey);
                }
            })
            // Core information of the conversation
            let chatsData = {
                privateMsgMaxId: state.privateMsgMaxId,
                groupMsgMaxId: state.groupMsgMaxId,
                chatKeys: chatKeys
            }
            localForage.setItem(key, chatsData)
            // Clean up deleted sessions
            state.chats = state.chats.filter(chat => !chat.delete)
        },
        clear(state) {
            cacheChats = []
            state.chats = [];
            state.activeChat = null;
        }
    },
    actions: {
        loadChat(context) {
            return new Promise((resolve, reject) => {
                let userId = userStore.state.userInfo.id;
                let key = "chats-" + userId;
                console.log('------------------------userId & key', userId, key, localForage.getItem(key))
                localForage.getItem(key).then((chatsData) => {
                    console.log('chatsData', chatsData)
                    if (!chatsData) {
                        resolve();
                    } else if (chatsData.chats) {
                        // Compatible with old versions
                        context.commit("initChats", chatsData);
                        resolve();
                    } else if (chatsData.chatKeys) {
                        const promises = [];
                        chatsData.chatKeys.forEach(key => {
                            promises.push(localForage.getItem(key))
                        })
                        Promise.all(promises).then(chats => {
                            chatsData.chats = chats.filter(o => o);
                            context.commit("initChats", chatsData);
                            resolve();
                        })
                    }
                }).catch((e) => {
                    console.log("Loading message failed")
                    reject();
                })
            })
        }
    },
    getters: {
        isLoading: (state) => () => {
            return state.loadingPrivateMsg || state.loadingGroupMsg
        },
        findChats: (state, getters) => () => {
            console.log('state.chats', state.chats)
            console.log('cacheChats', cacheChats)
            // if (cacheChats && getters.isLoading()) {
            if (cacheChats && getters.isLoading()) {
                return cacheChats;
            }
            return state.chats;
        },
        findChatIdx: (state, getters) => (chat) => {
            let chats = getters.findChats();
            for (let idx in chats) {
                if (chats[idx].type == chat.type &&
                    chats[idx].targetId === chat.targetId) {
                    chat = chats[idx];
                    return idx
                }
            }
        },
        findChat: (state, getters) => (msgInfo) => {
            let chats = getters.findChats();
            console.log('findChat', chats)
            // Get the other party's ID or group ID
            let type = msgInfo.groupId ? 'GROUP' : 'PRIVATE';
            let targetId = msgInfo.groupId ? msgInfo.groupId : msgInfo.selfSend ? msgInfo.recvId : msgInfo.sendId;
            let chat = null;
            for (let idx in chats) {
                if (chats[idx].type == type &&
                    chats[idx].targetId === targetId) {
                    chat = chats[idx];
                    break;
                }
            }
            return chat;
        },
        findChatByFriend: (state, getters) => (fid) => {
            let chats = getters.findChats();
            return chats.find(chat => chat.type == 'PRIVATE' &&
                chat.targetId == fid)
        },
        findChatByGroup: (state, getters) => (gid) => {
            let chats = getters.findChats();
            return chats.find(chat => chat.type == 'GROUP' &&
                chat.targetId == gid)
        },
        findMessage: (state) => (chat, msgInfo) => {
            if (!chat) {
                return null;
            }
            for (let idx in chat.messages) {
                if (msgInfo.id && chat.messages[idx].id == msgInfo.id) {
                    return chat.messages[idx];
                }
                // The message being sent may not have an ID, only a tmpId
                if (msgInfo.tmpId && chat.messages[idx].tmpId &&
                    chat.messages[idx].tmpId == msgInfo.tmpId) {
                    return chat.messages[idx];
                }
            }
        }
    }
}